package com.xxx.oauth.client;

import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * OAuth2 realm
 */
public class OAuth2Realm extends AuthorizingRealm {

	private String clientId;
	private String clientSecret;
	private String accessTokenUrl;
	private String userInfoUrl;
	private String redirectUrl;

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	public void setClientSecret(String clientSecret) {
		this.clientSecret = clientSecret;
	}

	public void setAccessTokenUrl(String accessTokenUrl) {
		this.accessTokenUrl = accessTokenUrl;
	}

	public void setUserInfoUrl(String userInfoUrl) {
		this.userInfoUrl = userInfoUrl;
	}

	public void setRedirectUrl(String redirectUrl) {
		this.redirectUrl = redirectUrl;
	}

	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof OAuth2Token;// 表示此Realm只支持OAuth2Token类型
	}

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		return authorizationInfo;
	}

	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		OAuth2Token oAuth2Token = (OAuth2Token) token;
		String code = oAuth2Token.getAuthCode(); // 授权码
		String username = extractUsername(code); // username
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, code, getName());
		return authenticationInfo;
	}

	/**
	 * 获取username
	 * @param code
	 * @return
	 */
	private String extractUsername(String code) {
		try {
			OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

			// 1.请求accessToken
			// 组装accessToken请求
			OAuthClientRequest accessTokenRequest = OAuthClientRequest
						.tokenLocation(accessTokenUrl)
						.setGrantType(GrantType.AUTHORIZATION_CODE)
						.setClientId(clientId)
						.setClientSecret(clientSecret)
						.setCode(code)
						.setRedirectURI(redirectUrl)
						.buildQueryMessage();
			OAuthAccessTokenResponse oAuthResponse = oAuthClient
					.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
			String accessToken = oAuthResponse.getAccessToken();
			Long expiresIn = oAuthResponse.getExpiresIn();
			System.out.println("accessToken:"+accessToken);
			System.out.println("expiresIn:"+expiresIn);

			// 2.请求资源服务器（userInfo）
			OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(userInfoUrl)
								.setAccessToken(accessToken)
								.buildQueryMessage();
			OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET,
								OAuthResourceResponse.class);
			String username = resourceResponse.getBody(); // 资源服务器返回的用户资源信息
			return username;
		} catch (Exception e) {
			System.err.println(e);
			throw new OAuth2AuthenticationException(e);
		}
	}
}
